package com.gitee.wsl.security.rbac

import com.gitee.wsl.ext.map.sortByKey
import com.gitee.wsl.security.rbac.UserCategory.Companion.ROOT_USER_GROUP
import com.gitee.wsl.struct.category.CategoryItemWarp

/**
 * 定义入口
 */
fun permissionAccessSystem(accessHandler: RoleBasedAccessScope.()->Unit): RoleBasedAccessControl {
    val roleBasedAccessControlImp = RoleBasedAccessControlImp()
    accessHandler(roleBasedAccessControlImp)
    return roleBasedAccessControlImp
}

/**
 *
 * 关系如下:
 *   对象 -- <定义>  --权限
 *   用户 -- 用户组 -- <对应> -- 角色
 *   角色 -- <拥有> --权限
 *
 */

interface RoleBasedAccessScope{

    /**
     * 定义 组织 结构 树
     */
    fun userGroup(userGroupHandler : UserGroupScope.()->Unit)

    fun permissionGroup(groupName:String,vararg permission:String)

    /**
     * 定义 实体 (级对应权限) 树
     */
    fun subject(subjectHandler: SubjectScope.()->Unit)

    /**
     * 用于生成 基本角色权限 可用于其它 角色 引用
     */
    fun ruleBaseOnSubject(rule : String)

    fun rule(rule : String , permissionHandler: RulePermissionScope.()->Unit)

    fun rule(rule : String , baseRule:String, permissionHandler: RulePermissionScope.()->Unit)

}


class RoleBasedAccessControlContext{

    /**
     * 定义
     */
    //对象
    val subjectTree = SubjectCategory.ROOT_GROUP

    //对象 权限定义
    val subjectPermissionCategory = SubjectPermissionCategory.ROOT_GROUP

    //权限分组
    val permissionGroupList = mutableListOf<PermissionGroup>()

    //用户
    val userGroupTree = ROOT_USER_GROUP
    val userRoleMap = mutableMapOf<User, UserRole>()

    //角色
    val allRole= mutableListOf<Role>()

    //角色对象权限
    val rolePermissionMap= mutableMapOf<Role, RoleSubjectPermissionCategory>()

}

interface RoleBasedAccessControl{
   fun login(user:String)
   fun loginOut()
   fun hasPermission(vararg permission: String):Boolean
   fun hasSubjectPermission(subjectTreeNode:List<String>,vararg permission: String):Boolean
}

class RoleBasedAccessControlImp: RoleBasedAccessControl, RoleBasedAccessScope {
    val context = RoleBasedAccessControlContext()

    var currentUser: User?=null

    var currentRoleList = mutableSetOf<Role>()

    val roleCompPermission: RoleSubjectPermissionCategoryComp?=null

    private fun findUserInUserGroup(userGroup: UserCategory, user: User): UserCategory?{
        if(userGroup.contains(user)) return userGroup
        userGroup.subItemList.forEach { category ->
            findUserInUserGroup(category as UserCategory,user)?.let { return it }
        }
        return null
    }

    private fun findUserListByName(user: String):List<User>{
        val retList= mutableListOf<User>()
        findUserInUserGroup(context.userGroupTree, User(user))?.let {
            currentUser= User(user)
            retList.add(currentUser!!)
            var parentUserCategory=it
            while(!parentUserCategory.isRoot){
                retList.add(parentUserCategory.data as User)
                parentUserCategory= parentUserCategory.parent as UserCategory
            }
        }
        return retList
    }

    override fun login(user: String) {
        findUserListByName(user).forEach { user->
            context.userRoleMap[user]?.let {
                currentRoleList.addAll(it.listRole)
            }
        }
    }

    override fun loginOut() {
        currentUser = null
        currentRoleList.clear()
    }

    override fun hasSubjectPermission(
        subjectTreeNode: List<String>,
        vararg permission: String
    ): Boolean {
        currentUser?:return false

        currentRoleList.forEach {role->
            context.rolePermissionMap[role]?.let {root->
                 if(RoleSubjectPermissionCategory.hasSubjectPermission(
                         root,
                         subjectTreeNode,
                         *permission
                     )
                 )
                     return true
            }
        }
        return false
    }

    override fun hasPermission(vararg permission: String):Boolean {
       return hasSubjectPermission(listOf(Subject.DEFAULT.name), *permission)
    }

    private fun createUserTree(node: UserCategory, userGroupScope: UserGroupScopeImp){
        val newUserGroup= UserGroup(userGroupScope.name) .apply {
                 userGroupScope.userList?.map { User(it) }?.let {
                     this.userList.addAll(it)
                 }
             }
        val newNodeEntry= UserCategory(newUserGroup)
        node.addSubCategoryItem(newNodeEntry  as CategoryItemWarp)
        userGroupScope.subUserGroupList.forEach {
            createUserTree(newNodeEntry,it)
        }
    }

    override fun userGroup(userGroupHandler: UserGroupScope.() -> Unit) {
        val groupConfig= UserGroupScopeImp()
        userGroupHandler(groupConfig)
        createUserTree(context.userGroupTree,groupConfig)
    }

    override fun permissionGroup(groupName: String, vararg permission: String) {
        context.permissionGroupList.find { it.name==groupName }?.let { permissionGroup->
            permission.forEach {
                permissionGroup.permissionList.add(Permission(it))
            }
        }?:context.permissionGroupList.add(PermissionGroup(groupName).apply {
            permission.forEach {
                permissionList.add(Permission(it))
            }
        })
    }


    private fun createSubjectTree(node: SubjectCategory, subjectScope: SubjectScopeImp){
        subjectScope.subjectScopeList.forEach {
            val subtreeNode= SubjectCategory(Subject(it.name))
            node.add(subtreeNode as CategoryItemWarp)
            createSubjectTree(subtreeNode,it)
        }
    }

    private fun createSubjectPermissionTree(node: SubjectPermissionCategory, subjectScope: SubjectScopeImp){
        subjectScope.permissionList?.let {permissionList->
            (node.data as SubjectPermission).permissionList.addAll(permissionList.map { Permission(it) })
        }
        subjectScope.subjectScopeList.forEach {
            val subtreeNode= SubjectPermissionCategory(SubjectPermission(Subject(it.name)))
            node.add(subtreeNode as CategoryItemWarp)
            createSubjectPermissionTree(subtreeNode,it)
        }
    }

    override fun subject(subjectHandler: SubjectScope.() -> Unit) {
        val subjectScope= SubjectScopeImp()
        subjectHandler(subjectScope)
        createSubjectTree(context.subjectTree,subjectScope)
        createSubjectPermissionTree(context.subjectPermissionCategory,subjectScope)
    }


    override fun ruleBaseOnSubject(rule: String) {

    }

    private fun buildRulePermission(node: RoleSubjectPermissionCategory, subjectList:List<String>, rulePermissionScope: SubjectPermissionScopeImp){
        var treeNode: RoleSubjectPermissionCategory? = null
        if(subjectList.isNotEmpty()) {
            treeNode = node.getSubjectPermissionCategory(subjectList[0])
            if (treeNode == null) {
                treeNode = RoleSubjectPermissionCategory(
                    RoleSubjectPermission(
                        node.roleNode.role, SubjectPermission(
                            Subject(subjectList[0]),
                            mutableListOf()
                        )
                    )
                )
                node.addSubCategoryItem(treeNode as CategoryItemWarp)
            }
            if (subjectList.size > 1)
                buildRulePermission(
                    treeNode,
                    subjectList.subList(1, subjectList.size),
                    rulePermissionScope
                )
            else {
                (treeNode.data as RoleSubjectPermission).apply {
                    isAbleAll = isAbleAll or rulePermissionScope.isAbleAll
                    if (!isAbleAll)
                        isDisableAll = isDisableAll or rulePermissionScope.isDisableAll
                    subjectPermission.permissionList.apply {
                        rulePermissionScope.grantPermissionList?.map { Permission(it) }?.let {
                            this.addAll(it)
                        }
                        if(rulePermissionScope.copyFromParent){
                            this.addAll(node.roleNode.subjectPermission.permissionList)
                        }
                    }
                }
            }
        }
    }

    override fun rule(rule: String, permissionHandler: RulePermissionScope.() -> Unit) {
        val rulePermissionScope= RulePermissionScopeImp()
        permissionHandler(rulePermissionScope)

        //rule entiry check
        val roleEntry= Role(rule)
        context.allRole.add(roleEntry)

        //rule user check
        rulePermissionScope.userList?.forEach { userName->
            val user= User(userName)
            val userRole= context.userRoleMap[user]
             if(userRole!=null)
                 userRole.listRole.add(roleEntry)
            else{
                 val newUserRole= UserRole(User(userName), mutableListOf(roleEntry))
                 context.userRoleMap[newUserRole.user] =newUserRole
             }
        }

        var rolePermissionScopeCategoryRoot = context.rolePermissionMap[roleEntry]
        if(rolePermissionScopeCategoryRoot == null) {
            rolePermissionScopeCategoryRoot= RoleSubjectPermissionCategory(
                RoleSubjectPermission(roleEntry, SubjectPermission(Subject.DEFAULT,
                    mutableListOf<Permission>().apply {
                        rulePermissionScope.grantPermissionList?.map { Permission(it) }
                            ?.let { addAll(it) }
                    }
                )).apply {
                    isAbleAll=rulePermissionScope.isAbleAll
                    isDisableAll=rulePermissionScope.isDisableAll
                    baseRule=rulePermissionScope.baseRuleName
                }
            )
            context.rolePermissionMap[roleEntry] = rolePermissionScopeCategoryRoot
        }

        //rule subject permission check
        /*rulePermissionScope.permissionScopeMap.toSortedMap(Comparator { o1, o2 ->
            o1.size-o2.size
        }).forEach {
            buildRulePermission(rolePermissionScopeCategoryRoot,it.key, it.value)
        }*/

        rulePermissionScope.permissionScopeMap.sortByKey{ o1, o2 ->
            o1.size-o2.size }.forEach {
            buildRulePermission(rolePermissionScopeCategoryRoot,it.key, it.value)
        }

    }

    override fun rule(
        rule: String,
        baseRule: String,
        permissionHandler: RulePermissionScope.() -> Unit
    ) {
        val rulePermissionScope= RulePermissionScopeImp()
        permissionHandler(rulePermissionScope)
    }


    companion object{
        /**
         * 工具类,如跟据定义 生成 ->对象权限定义类,便于后期引用
         *
         */
        fun printSubjectPermissionDefine(subjectPermission: SubjectPermissionCategory, level:Int=0){
            val item = subjectPermission.data as SubjectPermission
            if(item.permissionList.isEmpty())
                return

            val lineStart="  ".repeat(level)
            println( "$lineStart object ${item.subject.name.replace(" ","_").uppercase()} {")
            item.permissionList.forEach {
                println("$lineStart  const val ${it.name.replace(" ","_").uppercase()}=\"${it.name}\"")
            }
            subjectPermission.subItemList.forEach {
                printSubjectPermissionDefine(it as SubjectPermissionCategory,level+1)
            }
            println("$lineStart }")
        }
    }

}









